home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Atlanta_1990 / Atlanta-Devcon.1 / Libraries / Intuition / boopsi / mygroupgclass.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-26  |  12.8 KB  |  513 lines

  1. /* mygroupgclass.c -- :ts=8
  2.  * Example of a "gadget group subclass"
  3.  * which creates composite gadgets for demo 5.
  4.  */
  5.  
  6. /*
  7. Copyright (c) 1989, 1990 Commodore-Amiga, Inc.
  8.  
  9. Executables based on this information may be used in software
  10. for Commodore Amiga computers. All other rights reserved.
  11. This information is provided "as is"; no warranties are made.
  12. All use is at your own risk, and no liability or responsibility
  13. is assumed.
  14. */
  15.  
  16. #include "sysall.h"
  17. #include <intuition/classes.h>
  18. #include "mymodel.h"        /* attributes are defined there    */
  19.  
  20. #define D(x)    ;
  21.  
  22. #ifdef printf
  23. #undef printf
  24. #endif
  25. #define printf kprintf
  26.  
  27. #define G(o)     ((struct Gadget *) (o))
  28.  
  29. /* private class    */
  30. #define MYCLASSID    (NULL)
  31. extern struct Library    *IntuitionBase;
  32. #define SUPERCLASSID    GROUPGCLASS
  33.  
  34. struct MyGroupData    {
  35.     Object        *mgd_MyModel;
  36.     struct Image    *mgd_UpImage; 
  37.     struct Image    *mgd_DownImage;
  38. };
  39.  
  40. Class    *
  41. initMyGroupClass()
  42. {
  43.     ULONG __saveds    dispatchMyGroup();
  44.     ULONG    hookEntry();
  45.     Class    *cl;
  46.     Class    *MakeClass();
  47.  
  48.     void    *modclass;
  49.     void    *initMyModClass();
  50.  
  51.     D( printf("INITMYGROUPGCLASS\n"));
  52.  
  53.     if ( ! ( modclass = initMyModClass() ) )
  54.     {
  55.     D( printf("mgg: couldn't get modelclass\n" ));
  56.     return ( NULL );
  57.     }
  58.  
  59.     D( printf("initMC got modclass at %lx\n", modclass ) );
  60.  
  61.     if ( cl =  MakeClass( MYCLASSID, 
  62.         SUPERCLASSID, NULL,        /* superclass is public      */
  63.          sizeof ( struct MyGroupData ),
  64.         0 ))
  65.     {
  66.     /* initialize the cl_Dispatcher Hook    */
  67.     cl->cl_Dispatcher.h_Entry = hookEntry;
  68.     cl->cl_Dispatcher.h_SubEntry = dispatchMyGroup;
  69.     cl->cl_Dispatcher.h_Data = (VOID *) 0xFACE;    /* unused */
  70.  
  71.     /* keep track of this class handle for use in OM_NEW
  72.      * and freeMyGroupClass()
  73.      */
  74.     cl->cl_UserData = (ULONG) modclass;
  75.     }
  76.     return ( cl );
  77. }
  78.  
  79. freeMyGroupClass( cl )
  80. Class    *cl;
  81. {
  82.     int success = TRUE;
  83.  
  84.     if ( cl )
  85.     {
  86.     success = freeMyModClass( cl->cl_UserData );
  87.     }
  88.     /* don't try to free if the model class didn't free    */
  89.     return ( success? FreeClass( cl ): FALSE  );
  90. }
  91.  
  92. ULONG __saveds
  93. dispatchMyGroup( cl, o, msg )
  94. Class   *cl;
  95. Object  *o;
  96. Msg     msg;
  97. {
  98.     Object          *newobj;
  99.     struct MyGroupData    *mgd;
  100.  
  101.     mgd = INST_DATA( cl, o );
  102.  
  103.     switch ( msg->MethodID )
  104.     {
  105.     case OM_NEW:
  106.     D( printf("myg: om_new\n"));
  107.  
  108.     if ( newobj = (Object *) DSM( cl, o, msg ) )
  109.     {
  110.         if ( ! initMyGroupObject( cl, newobj, msg ) )
  111.         {
  112.         D( printf("om_new: iMGO failed\n") );
  113.         /* free what's there if failure    */
  114.             CoerceMethod( cl, newobj, OM_DISPOSE );
  115.         newobj = NULL;
  116.         }
  117.         else
  118.         {
  119.         D( printf("om_new: iMGO succeeded, set atts\n"));
  120.         /* superclass already initialized, don't
  121.          * propagate attributes up to group gadget
  122.          * again now.
  123.          */
  124.         setMyGroupAttrs( cl, newobj, msg );
  125.         }
  126.     }
  127.     D( printf("mygroup: OM_NEW returning %lx\n", newobj ) );
  128.     return ( (ULONG) newobj );
  129.  
  130.     case OM_GET:    
  131.     return ( (ULONG) getMyGroupAttrs( cl, o, msg ) );
  132.  
  133.     case OM_UPDATE:    
  134.     /* delegated to the model and superclass within in setMyGroupAttrs() */
  135.     case OM_SET:    
  136.  
  137.     /* this time, we want to let our superclass know about
  138.      * certain things.
  139.      */
  140.     return ( (ULONG) setMyGroupAttrs( cl, o, msg ) );
  141.  
  142.     case OM_DISPOSE:
  143.     /* dispose of components    */
  144.     D( printf("mygroup: dispose model\n"));
  145.         DM( mgd->mgd_MyModel, msg );    /* dispose model (and IC's)    */
  146.     D( printf("mygroup: dispose self and components\n"));
  147.     DSM( cl, o, msg );        /* dispose self and component gadgets */
  148.     D( printf("mygroup: dispose upimage\n"));
  149.     DM( mgd->mgd_UpImage, msg );
  150.     D( printf("mygroup: dispose downimage\n"));
  151.     DM( mgd->mgd_DownImage, msg );
  152.     break;
  153.  
  154.     default:    /* let the superclass handle it */
  155.     return ( (ULONG) DSM( cl, o, msg ) );
  156.     }
  157.     return ( 1 );
  158. }
  159.  
  160. #define PWIDTH        (120)    /* width of horizontal propslider    */
  161. #define SWIDTH        (50)    /* width of string gadget        */
  162.  
  163. enum gadgetids {
  164.     gUp = 1,
  165.     gDown,
  166.     gSlider,
  167.     gString,
  168.     gGroup,
  169. };
  170.  
  171. /* a macro for the "adjacent" position to the right of a gadget,
  172.  * but safe, if the reference gadget is NULL
  173.  */
  174. #define RIGHTBY( g )    ( ((g)==NULL)? 20: ((g)->LeftEdge + (g)->Width ) )
  175.  
  176. /****************************************************************/
  177. /*  mapping tag lists                        */
  178. /****************************************************************/
  179.  
  180. struct TagItem    slider2model[] = {
  181.     {PGA_TOP, MYMODA_CURRVAL},
  182.     {TAG_END, }
  183. };
  184.  
  185. struct TagItem    model2slider[] = {
  186.     {MYMODA_CURRVAL, PGA_TOP},
  187.     {MYMODA_RANGE, PGA_TOTAL },
  188.     {TAG_END, }
  189. };
  190.  
  191. struct TagItem    string2model[] = {
  192.     {STRINGA_LongVal, MYMODA_CURRVAL},
  193.     {TAG_END, }
  194. };
  195.  
  196. struct TagItem    model2string[] = {
  197.     {MYMODA_CURRVAL, STRINGA_LongVal},
  198.     {TAG_END, }
  199. };
  200.  
  201. struct TagItem    uparrow2model[] = {
  202.     {GA_ID, MYMODA_INCRSTROBE},
  203.     {TAG_END, }
  204. };
  205.  
  206. struct TagItem    downarrow2model[] = {
  207.     {GA_ID, MYMODA_DECRSTROBE},
  208.     {TAG_END, }
  209. };
  210.  
  211. /****************************************************************/
  212. /* tag lists for creating objects                */
  213. /****************************************************************/
  214.  
  215.  
  216. struct TagItem    proptags[] = {
  217.     {GA_WIDTH,        PWIDTH},    /* height to be specified    */
  218.     /* {ICA_TARGET,    XXX }, * will be model object    */
  219.     {ICA_MAP,        (ULONG) &slider2model[0]},
  220.     {PGA_FREEDOM,    FREEHORIZ},
  221.     {PGA_VISIBLE,    1},        /* want an integer value slider    */
  222.     {TAG_END ,}
  223. };
  224.  
  225. struct TagItem    stringtags[] = {
  226.     {GA_WIDTH,        SWIDTH},
  227.     {GA_HEIGHT,        12},        /* fix this    */
  228.     /* {ICA_TARGET,    XXXX },        will be model object    */
  229.     {ICA_MAP,        (ULONG) &string2model[0]},
  230.     {STRINGA_MaxChars,    10},
  231.     {STRINGA_LongVal,    0},        /* make it an integer gadget */
  232.     {STRINGA_Justification,
  233.                 STRINGRIGHT},
  234.     {TAG_END, }
  235. };
  236.  
  237.  
  238. /*
  239.  * Return TRUE if I could do everything needed
  240.  * to initialize one of my objects.
  241.  */
  242. initMyGroupObject( cl, o, msg )
  243. Class   *cl;
  244. Object  *o;
  245. struct opSet    *msg;
  246. {
  247.     struct DrawInfo    *drinfo;
  248.     struct Gadget    *g;
  249.     Object        *ic;
  250.     WORD        nextleft;
  251.  
  252.     struct MyGroupData    *mgd = INST_DATA( cl, o );
  253.     struct TagItem    *tags = msg->ops_AttrList;
  254.  
  255.     D( printf("iMGO in\n"));
  256.  
  257.     /* DrawInfo is required    */
  258.     if ( ! (drinfo = (struct DrawInfo *) GetTagData( GA_DRAWINFO, 0,  tags ) ) )
  259.     {
  260.     D( printf("iMGO didn't get the needed drawinfo\n"));
  261.     return ( FALSE );
  262.     }
  263.  
  264.     D( printf("iMGO got drawinfo at %lx\n", drinfo));
  265.  
  266.     /* get images for the up and down arrows, sensitive
  267.      * to depth and pen specs for current screen (we'll be
  268.      * adding resolution/size selection later).
  269.      */
  270.     mgd->mgd_UpImage = (struct Image *) NewObject( NULL, "sysiclass",
  271.     SYSIA_Size,    0,        /* normal "medium-res" for now */
  272.     SYSIA_DrawInfo, drinfo,
  273.     SYSIA_Which,    UPIMAGE,
  274.         TAG_END );
  275.  
  276.     D( printf("iMGO 1\n"));
  277.  
  278.     mgd->mgd_DownImage = (struct Image *) NewObject( NULL, "sysiclass",
  279.     SYSIA_Size,    0,        /* normal "medium-res" for now */
  280.     SYSIA_Which,    DOWNIMAGE,
  281.     SYSIA_DrawInfo, drinfo,
  282.         TAG_END );
  283.  
  284.     D( printf("iMGO 2\n"));
  285.  
  286.     /* Allocate model: we have a pointer to the model class
  287.      * stashed in cl_UserData for just this occasion.
  288.      *
  289.      * Target of model's UPDATE notification is set when
  290.      * user sets the group gadget attribute and map.
  291.      */
  292.     D( printf("get model object, class at %lx\n", cl->cl_UserData ) );
  293.     mgd->mgd_MyModel =  (Object *) NewObject( cl->cl_UserData, NULL, 
  294.             TAG_END );
  295.     D( printf("model at %lx\n", mgd->mgd_MyModel ) );
  296.  
  297.     if ( ! mgd->mgd_MyModel ) return ( FALSE );    /* I really need this guy */
  298.  
  299.     /* get the string gadget    */
  300.     g  = (struct Gadget *) NewObject( NULL, "strgclass",
  301.         GA_LEFT,    0,
  302.     ICA_TARGET,    mgd->mgd_MyModel,
  303.     TAG_MORE,    stringtags,
  304.     TAG_END );
  305.     D( printf( "string gadget at %lx\n", g ) );
  306.     nextleft = RIGHTBY( g );
  307.  
  308.     /* add it to the group ... which is myself    */
  309.     DoMethod( G(o), OM_ADDMEMBER, g );
  310.  
  311.     /* The string gadget now talks to the model.
  312.      * Add an interconnection from the model to
  313.      * the string gadget.
  314.      */
  315.     ic = (Object *) NewObject( NULL, ICCLASS,
  316.             ICA_TARGET,    g,
  317.         ICA_MAP,    model2string,
  318.         TAG_END );
  319.     DoMethod( mgd->mgd_MyModel, OM_ADDMEMBER, ic );
  320.  
  321.     D( printf("iMGO 1\n"));
  322.  
  323.     /* get the prop gadget, immediately to the right of the string */
  324.     g = (struct Gadget *) NewObject( NULL, "propgclass",
  325.     GA_LEFT,    nextleft,
  326.     GA_HEIGHT,    mgd->mgd_DownImage? mgd->mgd_DownImage->Height: 20,
  327.     ICA_TARGET,    mgd->mgd_MyModel,
  328.     TAG_MORE,    proptags,
  329.     TAG_END );
  330.     D( printf( "prop gadget returned: %lx\n", g ) );
  331.     nextleft = RIGHTBY( g );
  332.  
  333.     /* add it to the group ...    */
  334.     DoMethod( G(o), OM_ADDMEMBER, g );
  335.  
  336.     /* ... and get an ic for the prop gadget    */
  337.     ic = (Object *) NewObject( NULL, ICCLASS,
  338.             ICA_TARGET,    g,
  339.         ICA_MAP,    model2slider,
  340.         TAG_END );
  341.     DoMethod( mgd->mgd_MyModel, OM_ADDMEMBER, ic );
  342.  
  343.     /* down button is immediately to the right ...    */
  344.     g = (struct Gadget *) NewObject( NULL, "buttongclass",
  345.     GA_IMAGE,     mgd->mgd_DownImage,
  346.     GA_LEFT,    nextleft,
  347.     GA_ID,        gDown,
  348.     /* interconnections ...    */
  349.     ICA_TARGET,    mgd->mgd_MyModel,
  350.     ICA_MAP,    &downarrow2model[0],
  351.     TAG_END );
  352.     D( printf("downgadget at %lx\n", g ));
  353.     nextleft = RIGHTBY( g );
  354.  
  355.     /* ... and add it to the group gadget    */
  356.     DoMethod( G(o), OM_ADDMEMBER, g );
  357.  
  358.     /* the buttons don't need to hear from the model, 
  359.      * hence, no ic's for them.
  360.      */
  361.  
  362.     /* up arrow button    */
  363.     g = (struct Gadget *) NewObject( NULL, "buttongclass",
  364.     GA_IMAGE,     mgd->mgd_UpImage,
  365.     GA_LEFT,    nextleft,
  366.     GA_ID,        gUp,
  367.     /* interconnections ...    */
  368.     ICA_MAP,    &uparrow2model[0],
  369.     ICA_TARGET,    mgd->mgd_MyModel,
  370.     TAG_END );
  371.     D( printf("upgadget at %lx\n", g ));
  372.  
  373.     /* ... and add it to the group gadget    */
  374.     DoMethod( G(o), OM_ADDMEMBER, g );
  375.  
  376.     D(printf("all components initialized\n"));
  377.  
  378.     return ( TRUE );
  379. }
  380.  
  381.  
  382.  
  383.  
  384.  
  385.  
  386.  
  387.  
  388.  
  389.  
  390. /** Filter and Delegate Slept Here **/
  391.  
  392. /* I'll pass along these to the model, and
  393.  * withhold them from my ancestors
  394.  */
  395. Tag    model_attrs[] = {
  396.     MYMODA_CURRVAL,
  397.     MYMODA_RANGE,
  398.     ICA_TARGET,
  399.     ICA_MAP,
  400.     TAG_END,
  401. };
  402.  
  403.  
  404. getMyGroupAttrs( cl, o, msg )
  405. Class        *cl;
  406. Object        *o;
  407. struct opGet    *msg;
  408. {
  409.     struct MyGroupData    *mgd = INST_DATA( cl, o );
  410.  
  411.     /* delegate attribute responsibility to model,
  412.      * for attributes it understands.  Others
  413.      * are handled by group gadget (superclass)
  414.      */
  415.  
  416.     if ( TagInArray( msg->opg_AttrID, model_attrs ) )
  417.     {
  418.     return ( DM( mgd->mgd_MyModel, msg ) );
  419.     }
  420.     /* else */
  421.     return ( DSM( cl, o, msg ) );
  422. }
  423.  
  424. /*
  425.  * This function is called for OM_NEW, OM_SET, and OM_UPDATE.
  426.  * What we do is delegate the processing of all the attributes
  427.  * that our model will understand to it, including the
  428.  * target/map.  These last means that the model will be
  429.  * directly connected to the outside world instead of
  430.  * directly our gadget itself.
  431.  *
  432.  * In the case of OM_NEW, I've already created the model with
  433.  * no attributes passed, now I have to convert the OM_NEW
  434.  * message into an OM_SET message so we don't go create
  435.  * another model object.
  436.  *
  437.  * Also, since the superclass has already seen the OM_NEW
  438.  * message and attributes, we don't pass it along again here,
  439.  * in that case.
  440.  */
  441. setMyGroupAttrs( cl, o, msg )
  442. Class        *cl;
  443. Object        *o;
  444. struct opSet    *msg;
  445. {
  446.     /* we're going to duplicate our tagitems and
  447.      * filter the cloned list.
  448.      */
  449.     struct TagItem    *origtags;
  450.     struct TagItem    *CloneTagItems();
  451.     ULONG        FilterTagItems();
  452.     void        RefreshTagItemClones();
  453.  
  454.     int            retval = 0;
  455.     struct MyGroupData    *mgd;
  456.  
  457.     mgd = INST_DATA( cl, o );
  458.  
  459.     /* going to delegate different pieces of the list
  460.      * to different objects, so I need to substitute
  461.      * a clone for the list passed to me.
  462.      */
  463.     origtags = msg->ops_AttrList;
  464.     msg->ops_AttrList = CloneTagItems( origtags );
  465.  
  466.     /* set attributes for model    */
  467.     D( dumpTagList( "debug 1", msg->ops_AttrList ) );
  468.     if ( FilterTagItems( msg->ops_AttrList, model_attrs, TAGFILTER_AND ) )
  469.     {
  470.     D( dumpTagList( "after filtering", msg->ops_AttrList ) );
  471.  
  472.     /* Pass along same message, with filtered attrlist
  473.      * This message will be mapped and propagated to all
  474.      * component gadgets, who will refresh themselves
  475.      * if needed.  There's no additional need to refresh
  476.      * the group gadget.
  477.      *
  478.      * For the case of OM_NEW, we have to convert to OM_SET,
  479.      * since we've previously created the thing.
  480.      */
  481.     D( printf("send filtered tags to my model (at %lx)\n", mgd->mgd_MyModel));
  482.  
  483.     if ( msg->MethodID == OM_NEW )
  484.     {
  485.         DoMethod(mgd->mgd_MyModel, OM_SET, msg->ops_AttrList, msg->ops_GInfo);
  486.     }
  487.     else
  488.     {
  489.         /* pass along OM_SET or OM_UPDATE message as is (with mapped tags). */
  490.         DM( mgd->mgd_MyModel, msg );
  491.     }
  492.     }
  493.  
  494.     if ( msg->MethodID != OM_NEW )
  495.     {
  496.     /* re-clone, without re-allocating    */
  497.     RefreshTagItemClones( msg->ops_AttrList, origtags );
  498.  
  499.     if ( FilterTagItems( msg->ops_AttrList, model_attrs, TAGFILTER_NOT ) )
  500.     {
  501.         /* Perhaps there is a need to refresh the group gadget now. */
  502.         D( printf("send to superclass\n"));
  503.         retval = DSM( cl, o, msg );
  504.     }
  505.     D( else printf("filter failed 2\n"));
  506.     }
  507.  
  508.     /* free clone and restore original */
  509.     FreeTagItems( msg->ops_AttrList );
  510.     msg->ops_AttrList = origtags ;
  511.     return ( retval );
  512. }
  513.